using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
using System.Xml;
using ChannelVN.Cached.Common;
using ChannelVN.CMS.Common;
using ChannelVN.Cached.Entity;

namespace ChannelVN.Cached.Config
{
    public class CacheSettings
    {
        private const string CacheNameForSettingFile = "COMMON_CONFIGURATION_CACHE_SETTING";
        private const int CacheExpireForSettingFile = 60 * 60 * 24; // 1 day
        private const int DefaultCachedExpireForMemcached = 180;
        private static CacheSettings _currentSetting;

        public static CacheSettings GetCurrentSettings()
        {
            if (Lib.IsWebApp)
            {
                var settings = HttpContext.Current.Cache[CacheNameForSettingFile];
                if (null == settings)
                {
                    try
                    {
                        var settingFilePath = HttpContext.Current.Server.MapPath(AppConfigs.CacheSettingFile);
                        settings = LoadSettingFile(settingFilePath);

                        var fileDependency = new CacheDependency(settingFilePath);
                        HttpContext.Current.Cache.Insert(CacheNameForSettingFile, settings, fileDependency, DateTime.Now.AddSeconds(CacheExpireForSettingFile), TimeSpan.Zero, CacheItemPriority.Normal, null);

                        return settings as CacheSettings;
                    }
                    catch
                    {
                        return null;
                    }
                }
                return settings as CacheSettings;
            }
            else
            {
                var settingFilePath = AppConfigs.CacheSettingFile;
                return LoadSettingFile(settingFilePath);
            }
        }

        public static CacheSettings LoadSettingFile(string filePath)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            if (null == xmlDoc.DocumentElement) return null;

            var settings = new CacheSettings();

            #region Cache config
            // Cache config
            var nodeEnableCache = xmlDoc.DocumentElement.SelectSingleNode("//CacheConfiguration");

            // Enable cached?
            settings.EnableCache = (!(null == nodeEnableCache || null == nodeEnableCache.Attributes) &&
                                    Lib.Object2Boolean(nodeEnableCache.Attributes["enable"].Value));

            // Enable cached for data?
            settings.EnableDataCached = (!(null == nodeEnableCache || null == nodeEnableCache.Attributes) &&
                                    Lib.Object2Boolean(nodeEnableCache.Attributes["enableDataCached"].Value));

            // Enable cached dependency?
            settings.EnableCacheDependency = (!(null == nodeEnableCache || null == nodeEnableCache.Attributes) &&
                                    Lib.Object2Boolean(nodeEnableCache.Attributes["enableDependency"].Value));

            // Enable dynamic layout?
            settings.EnableHtmlCached = (!(null == nodeEnableCache || null == nodeEnableCache.Attributes) &&
                                    Lib.Object2Boolean(nodeEnableCache.Attributes["enableHtmlCached"].Value));

            // Enable html cached?
            settings.EnableDynamicLayout = (!(null == nodeEnableCache || null == nodeEnableCache.Attributes) &&
                                    Lib.Object2Boolean(nodeEnableCache.Attributes["enableDynamicLayout"].Value));

            // Default cache expired
            settings.DefaultCacheExpire = (null == nodeEnableCache || null == nodeEnableCache.Attributes
                                               ? 0
                                               : Lib.Object2Integer(
                                                   GetXmlAttributeValue(nodeEnableCache.Attributes["defaultCacheExpire"])));
            if (settings.DefaultCacheExpire == 0) settings.DefaultCacheExpire = DefaultCachedExpireForMemcached;

            // Default cache expired
            settings.CacheClientForDataCached = (null == nodeEnableCache || null == nodeEnableCache.Attributes
                                               ? ""
                                               : Lib.Object2String(
                                                   GetXmlAttributeValue(nodeEnableCache.Attributes["cacheClientForDataCached"])));
            #endregion

            #region Cache client
            var nodeCacheClients = xmlDoc.DocumentElement.SelectNodes("//CacheConfiguration/CacheClient");
            var cacheClients = new List<CacheClientItem>();
            if (null != nodeCacheClients)
            {
                var cacheClientCount = nodeCacheClients.Count;
                for (var i = 0; i < cacheClientCount; i++)
                {
                    var xmlAttributeCollection = nodeCacheClients[i].Attributes;
                    if (xmlAttributeCollection == null) continue;
                    var cacheClient = new CacheClientItem
                                          {
                                              Name =
                                                  Lib.Object2String(
                                                      xmlAttributeCollection["name"].Value),
                                              ConfigSectionName = Lib.Object2String(
                                                  xmlAttributeCollection["configSectionName"].Value)
                                          };

                    var nodeCacheClientSettings = nodeCacheClients[i].SelectNodes("//Setting");
                    var cacheClientSettings = new List<CacheClientItem.CacheClientSetting>();
                    if (null != nodeCacheClientSettings)
                    {
                        var cacheClientSettingCount = nodeCacheClientSettings.Count;
                        for (var j = 0; j < cacheClientSettingCount; j++)
                        {
                            var attributeCollection = nodeCacheClientSettings[i].Attributes;
                            if (attributeCollection != null)
                                cacheClientSettings.Add(
                                    new CacheClientItem.CacheClientSetting(
                                        GetXmlAttributeValue(attributeCollection["key"]),
                                        GetXmlAttributeValue(attributeCollection["value"])));
                        }
                    }
                    cacheClient.CacheClientSettings = cacheClientSettings.ToArray();
                    cacheClients.Add(cacheClient);
                }
            }
            settings.CacheClients = cacheClients.ToArray();
            #endregion

            #region Pages
            var pageSetting = new PageSetting();

            var nodePageConfig = xmlDoc.DocumentElement.SelectSingleNode("//CacheObjects/Pages");

            // Cache Config section for page
            pageSetting.CacheClientName =
                Lib.Object2String(GetXmlAttributeValue(nodePageConfig.Attributes["cacheClientName"]));

            // List of page cache config
            var pageSettings = nodePageConfig.SelectNodes("//Page");
            var pageSettingItems = new List<PageSettingItem>();
            string[] extendQueryStrings;
            var pageCount = pageSettings.Count;
            for (var i = 0; i < pageCount; i++)
            {
                if (null == pageSettings[i].Attributes) continue;

                var pageSettingItem = new PageSettingItem
                                          {
                                              Name =
                                                  Lib.Object2String(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["name"])),
                                              PageFile =
                                                  Lib.Object2String(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["pageFile"])),
                                              ConditionForCreateUpdateCachedUrl =
                                                  Lib.Object2String(
                                                      GetXmlAttributeValue(
                                                          pageSettings[i].Attributes["conditionForCreateUpdateCachedUrl"])),
                                              QueryStringFormat =
                                                  Lib.Object2String(
                                                      GetXmlAttributeValue(
                                                          pageSettings[i].Attributes["queryStringFormat"])),
                                              GroupKey =
                                                  (CacheSettingConstants.GroupCachedKey) Lib.Object2Integer(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["groupKey"])),
                                              CacheNameFormat =
                                                  Lib.Object2String(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["cacheNameFormat"])),
                                              CacheExpire =
                                                  Lib.Object2Long(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["cacheExpired"])),
                                              EnableCache =
                                                  Lib.Object2Boolean(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["enableCached"])),
                                              EnableDynamicLayout =
                                                  Lib.Object2Boolean(
                                                      GetXmlAttributeValue(
                                                          pageSettings[i].Attributes["enableDynamicLayout"])),
                                              EnableViewState =
                                                  Lib.Object2Boolean(
                                                      GetXmlAttributeValue(pageSettings[i].Attributes["enableViewState"]))
                                          };
                if (pageSettingItem.CacheExpire == 0) pageSettingItem.CacheExpire = settings.DefaultCacheExpire;

                #region Controls
                var controlSetting = new ControlSetting();

                XmlNode nodeControlConfig = pageSettings[i].SelectSingleNode("//Controls");
                if (null != nodeControlConfig)
                {
                    // Cache Config section for page
                    controlSetting.CacheClientName = Lib.Object2String(GetXmlAttributeValue(nodeControlConfig.Attributes["cacheClientName"]));

                    // List of page cache config
                    var controlSettings = nodeControlConfig.SelectNodes("//Control");
                    var controlSettingItems = new List<ControlSettingItem>();
                    var controlCount = controlSettings.Count;
                    for (var j = 0; j < controlCount; j++)
                    {
                        var controlSettingItem = new ControlSettingItem
                                                     {
                                                         Name =
                                                             Lib.Object2String(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["name"])),
                                                         CacheNameFormat =
                                                             Lib.Object2String(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["cacheNameFormat"])),
                                                         GroupKey =
                                                             (CacheSettingConstants.GroupCachedKey) Lib.Object2Integer(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["groupKey"])),
                                                         CacheExpire =
                                                             Lib.Object2Long(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["cacheExpired"])),
                                                         EnableCache =
                                                             Lib.Object2Boolean(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["enableCached"])),
                                                         EnableDynamicLayout =
                                                             Lib.Object2Boolean(
                                                                 GetXmlAttributeValue(
                                                                     pageSettings[i].Attributes["enableDynamicLayout"])),
                                                         EnableViewState =
                                                             Lib.Object2Boolean(
                                                                 GetXmlAttributeValue(
                                                                     controlSettings[j].Attributes["enableViewState"]))
                                                     };
                        if (controlSettingItem.CacheExpire == 0) controlSettingItem.CacheExpire = settings.DefaultCacheExpire;

                        controlSettingItems.Add(controlSettingItem);
                    }
                    controlSetting.ControlSettingItems = controlSettingItems.ToArray();
                }

                pageSettingItem.ControlSettings = controlSetting;
                #endregion

                #region Extend query string for cached update

                string extendQueryString =
                    Lib.Object2String(
                        GetXmlAttributeValue(pageSettings[i].Attributes["extendQueryStringForCachedUpdate"]));
                if (!string.IsNullOrEmpty(extendQueryString))
                {
                    if (!extendQueryString.StartsWith("[")) extendQueryString = "[" + extendQueryString;
                    if (!extendQueryString.EndsWith("]")) extendQueryString = extendQueryString + "]";

                    try
                    {
                        pageSettingItem.ExtendQueryStringForCachedUpdates = NewtonJson.Deserialize<string[]>(extendQueryString);
                    }
                    catch
                    {
                        pageSettingItem.ExtendQueryStringForCachedUpdates = new string[] { };
                    }
                }
                else
                {
                    pageSettingItem.ExtendQueryStringForCachedUpdates = new string[] { };
                }
                #endregion

                pageSettingItems.Add(pageSettingItem);
            }
            pageSetting.PageSettingItems = pageSettingItems.ToArray();

            settings.PageSettings = pageSetting;
            #endregion

            return settings;
        }

        private static string GetXmlAttributeValue(XmlAttribute attribute)
        {
            return (null == attribute ? string.Empty : attribute.Value);
        }

        #region Properties

        public bool EnableCache { get; set; }

        public bool EnableDataCached { get; set; }

        public bool EnableCacheDependency { get; set; }

        public bool EnableDynamicLayout { get; set; }

        public bool EnableHtmlCached { get; set; }

        public long DefaultCacheExpire { get; set; }

        public string CacheClientForDataCached { get; set; }

        public PageSetting PageSettings { get; set; }

        public CacheClientItem[] CacheClients { get; set; }

        #endregion

        #region Class object
        //#region Cache client
        //public class CacheClientItem
        //{
        //    public string Name { get; set; }
        //    public string ConfigSectionName { get; set; }

        //    public CacheClientSetting[] CacheClientSettings { get; set; }

        //    public string GetCacheClientSetting(string key)
        //    {
        //        var count = CacheClientSettings.Length;
        //        for (var i = 0; i < count; i++)
        //        {
        //            if (CacheClientSettings[i].Key == key)
        //            {
        //                return CacheClientSettings[i].Value;
        //            }
        //        }
        //        return string.Empty;
        //    }

        //    public struct CacheClientSetting
        //    {
        //        public string Key;
        //        public string Value;

        //        public CacheClientSetting(string key, string value)
        //        {
        //            Key = key;
        //            Value = value;
        //        }
        //    }
        //}
        //#endregion

        //#region Page
        //public class PageSettingItem
        //{
        //    public string Name { get; set; }

        //    public string PageFile { get; set; }

        //    public string QueryStringFormat { get; set; }

        //    public bool IsGroupKey { get; set; }

        //    public string CacheNameFormat { get; set; }

        //    public long CacheExpire { get; set; }

        //    public bool EnableCache { get; set; }

        //    public bool EnableDynamicLayout { get; set; }

        //    public bool EnableViewState { get; set; }

        //    public string[] ExtendQueryStringForCachedUpdates { get; set; }

        //    public ControlSetting ControlSettings { get; set; }

        //    public PageSettingItem()
        //    {
        //        Name = "";
        //        PageFile = "";
        //        QueryStringFormat = "";
        //        IsGroupKey = false;
        //        CacheNameFormat = "";
        //        CacheExpire = 0L;
        //        EnableCache = false;
        //        EnableDynamicLayout = false;
        //        EnableViewState = true;
        //    }
        //}
        //public class PageSetting
        //{
        //    public string CacheClientName { get; set; }

        //    public PageSettingItem[] PageSettingItems { get; set; }

        //    public PageSettingItem this[string cacheName]
        //    {
        //        get
        //        {
        //            var count = PageSettingItems.Length;
        //            for (var i = 0; i < count; i++)
        //            {
        //                if (cacheName == PageSettingItems[i].Name)
        //                {
        //                    return PageSettingItems[i];
        //                }
        //            }
        //            return null;
        //        }
        //    }

        //    public PageSettingItem GetPageSettingByPageFile(string pageFile)
        //    {
        //        var count = PageSettingItems.Length;
        //        for (var i = 0; i < count; i++)
        //        {
        //            if (pageFile.ToLower() == PageSettingItems[i].PageFile.ToLower())
        //            {
        //                return PageSettingItems[i];
        //            }
        //        }
        //        return null;
        //    }
        //}
        //#endregion

        //#region Control
        //public class ControlSettingItem
        //{
        //    public string Name { get; set; }

        //    public string CacheNameFormat { get; set; }

        //    public bool IsGroupKey { get; set; }

        //    public long CacheExpire { get; set; }

        //    public bool EnableCache { get; set; }

        //    public bool EnableDynamicLayout { get; set; }

        //    public bool EnableViewState { get; set; }

        //    public ControlSettingItem()
        //    {
        //        Name = "";
        //        CacheNameFormat = "";
        //        IsGroupKey = false;
        //        CacheExpire = 0L;
        //        EnableCache = false;
        //        EnableDynamicLayout = false;
        //        EnableViewState = true;
        //    }
        //}
        //public class ControlSetting
        //{
        //    public string CacheClientName { get; set; }

        //    public ControlSettingItem[] ControlSettingItems { get; set; }

        //    public ControlSettingItem this[string cacheName]
        //    {
        //        get
        //        {
        //            var count = ControlSettingItems.Length;
        //            for (var i = 0; i < count; i++)
        //            {
        //                if (cacheName == ControlSettingItems[i].Name)
        //                {
        //                    return ControlSettingItems[i];
        //                }
        //            }
        //            return null;
        //        }
        //    }
        //}
        //#endregion
        #endregion
    }
}
